package com.googlecode.androidkurskoblenz.sockethelper;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class DeviceAdapter extends ArrayAdapter<Object>
{
	private class ViewItem
	{
		int headerContent = -1;
		int res;
		int visibility = View.VISIBLE;
		
		ViewItem(int res)
		{
			this.res = res;
		}
		
		ViewItem(int res, int headerContent)
		{
			this.res = res;
			this.headerContent = headerContent;
		}
	}
	
	private BluetoothAdapter bluetoothAdapter = null;
	private DeviceList deviceList;
	private List<BluetoothDevice> devices = new LinkedList<BluetoothDevice>();
	private boolean discoveryRunning;
	private IntentFilter filter;
	private ViewItem headerBluetooth, headerOther, headerPaired;
	private LayoutInflater inflater;
	private BroadcastReceiver receiver = new BroadcastReceiver()
	{
		@Override
		public void onReceive(Context context, Intent intent)
		{
			String action = intent.getAction();
			
			if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action))
			{
				int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
				int state_before = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.ERROR);
				
				if((state == BluetoothAdapter.STATE_ON && state_before != BluetoothAdapter.STATE_ON) ||
						(state != BluetoothAdapter.STATE_ON && state_before == BluetoothAdapter.STATE_ON))
					updateList();
				
				return;
			}
			
			if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action))
			{
				discoveryRunning = false;
				deviceList.onDiscoveryFinished();
				Toast.makeText(deviceList, R.string.msg_discovery_finished, Toast.LENGTH_SHORT).show();
				notifyDataSetChanged();
				return;
			}
			
			if(BluetoothDevice.ACTION_FOUND.equals(action))
			{
				BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
				addDevice(device, true);
				return;
			}
		}
	};
	private ViewItem viewBluetoothDiscovery, viewBluetoothEnable;
	
	public DeviceAdapter(DeviceList deviceList)
	{
		super(deviceList, 0);
		
		this.deviceList = deviceList;
		
		bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		inflater = (LayoutInflater) deviceList.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		
		filter = new IntentFilter();
		filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
		filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
		filter.addAction(BluetoothDevice.ACTION_FOUND);
		
		if(bluetoothAdapter == null)
		{
			super.add(new ViewItem(R.layout.list_item_header, R.string.header_bluetooth));
			super.add(new ViewItem(R.layout.list_item_bluetooth_unavailable));
		}
		else
		{
			viewBluetoothEnable = new ViewItem(R.layout.list_item_bluetooth_enable);
			viewBluetoothDiscovery = new ViewItem(R.layout.list_item_bluetooth);
			
			headerBluetooth = new ViewItem(R.layout.list_item_header, R.string.header_bluetooth);
			headerOther = new ViewItem(R.layout.list_item_header, R.string.header_other_devices);
			headerPaired = new ViewItem(R.layout.list_item_header, R.string.header_paired_devices);
			
			updateList();
		}
	}
	
	private void addDevice(BluetoothDevice device, boolean addToAdapter)
	{
		for(BluetoothDevice item : devices)
		{
			if(item.getAddress().equalsIgnoreCase(device.getAddress()))
				return;
		}
		
		if(!addToAdapter)
		{
			// only add to list, but not to adapter
			devices.add(0, device);
			return;
		}
		
		Object insertBefore =
				(device.getBondState() == BluetoothDevice.BOND_BONDED)
						? headerOther
						: viewBluetoothDiscovery;
		
		Object item;
		for(int i = 0; i < getCount(); i++)
		{
			item = getItem(i);
			
			if(item.equals(insertBefore))
			{
				super.insert(device, i);
				devices.add(0, device);
				break;
			}
		}
	}
	
	private void cancelDiscovery()
	{
		if(bluetoothAdapter != null)
			bluetoothAdapter.cancelDiscovery();
	}
	
	private View prepareView(ViewItem item, View convertView, ViewGroup parent) throws Exception
	{
		View v = inflater.inflate(item.res, parent, false);
		
		if(item.res == R.layout.list_item_header)
			((TextView) v).setText(item.headerContent);
		else if(item == viewBluetoothDiscovery)
		{
			TextView btn = (TextView) v.findViewById(R.id.btn_discovery);
			if(discoveryRunning)
				btn.setText(R.string.title_stop_discovery);
			btn.setOnClickListener(new OnClickListener()
			{
				@Override
				public void onClick(View v)
				{
					startDiscovery();
				}
			});
			
			v.findViewById(R.id.btn_preferences).setOnClickListener(new OnClickListener()
			{
				@Override
				public void onClick(View v)
				{
					Intent intentBluetooth = new Intent();
					intentBluetooth.setAction(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
					deviceList.startActivity(intentBluetooth);
				}
			});
		}
		else if(item.res == R.layout.list_item_bluetooth_unavailable)
		{}
		else if(item.res == R.layout.list_item_bluetooth_enable)
		{
			v.findViewById(R.id.btn_enable).setOnClickListener(new OnClickListener()
			{
				
				@Override
				public void onClick(View v)
				{
					deviceList.requestEnableBluetooth();
				}
			});
			
			v.findViewById(R.id.btn_preferences).setOnClickListener(new OnClickListener()
			{
				@Override
				public void onClick(View v)
				{
					Intent intentBluetooth = new Intent();
					intentBluetooth.setAction(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
					deviceList.startActivity(intentBluetooth);
				}
			});
		}
		else
			throw new Exception("Unknown resource: " + item.res);
		
		v.setVisibility(item.visibility);
		return v;
	}
	
	@SuppressLint("DefaultLocale")
	private View prepateDeviceView(BluetoothDevice item, View convertView, ViewGroup parent)
	{
		TextView tv;
		LinearLayout v = (LinearLayout) inflater.inflate(R.layout.list_item_device, parent, false);
		
		tv = (TextView) v.findViewById(R.id.list_name);
		tv.setText(item.getName());
		
		tv = (TextView) v.findViewById(R.id.list_address);
		tv.setText(item.getAddress().toUpperCase());
		
		if(bluetoothAdapter.isEnabled() == false)
			v.setVisibility(View.GONE);
		
		return v;
	}
	
	private void startDiscovery()
	{
		if(bluetoothAdapter == null)
			return;
		
		if(discoveryRunning)
		{
			cancelDiscovery();
			return;
		}
		
		discoveryRunning = true;
		deviceList.onDiscoveryStarted();
		bluetoothAdapter.startDiscovery();
		notifyDataSetChanged();
	}
	
	private void updateList()
	{
		if(bluetoothAdapter == null)
			return;
		
		setNotifyOnChange(false);
		
		if(bluetoothAdapter.isEnabled())
		{
			for(BluetoothDevice device : bluetoothAdapter.getBondedDevices())
				addDevice(device, false);
			
			super.clear();
			super.add(headerPaired);
			
			for(BluetoothDevice device : devices)
				if(device.getBondState() == BluetoothDevice.BOND_BONDED)
					super.add(device);
			
			super.add(headerOther);
			
			for(BluetoothDevice device : devices)
				if(device.getBondState() != BluetoothDevice.BOND_BONDED)
					super.add(device);
			
			super.add(viewBluetoothDiscovery);
		}
		else
		{
			super.clear();
			super.add(headerBluetooth);
			super.add(viewBluetoothEnable);
		}
		
		notifyDataSetChanged();
	}
	
	@Override
	@Deprecated
	public void add(Object object)
	{
		throw new UnsupportedOperationException();
	}
	
	@Override
	@Deprecated
	public void addAll(Collection<? extends Object> collection)
	{
		throw new UnsupportedOperationException();
	}
	
	@Override
	@Deprecated
	public void addAll(Object... items)
	{
		throw new UnsupportedOperationException();
	}
	
	@Override
	public boolean areAllItemsEnabled()
	{
		return false;
	}
	
	public View getView(int position, View convertView, ViewGroup parent)
	{
		Object item = super.getItem(position);
		
		try
		{
			if(item instanceof BluetoothDevice)
				return prepateDeviceView((BluetoothDevice) item, convertView, parent);
			else if(item instanceof ViewItem)
				return prepareView((ViewItem) item, convertView, parent);
			else
				throw new Exception("Unknown item in list: " + item.toString());
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}
	
	@Override
	public int getViewTypeCount()
	{
		return 5;
	}
	
	@Override
	@Deprecated
	public void insert(Object object, int index)
	{
		throw new UnsupportedOperationException();
	}
	
	@Override
	public boolean isEnabled(int position)
	{
		Object item = getItem(position);
		if(item instanceof BluetoothDevice)
			return true;
		return false;
	}
	
	public void onStart()
	{
		if(bluetoothAdapter == null)
			return;
		
		updateList();
		deviceList.registerReceiver(receiver, filter);
	}
	
	public void onStop()
	{
		if(bluetoothAdapter == null)
			return;
		cancelDiscovery();
		deviceList.unregisterReceiver(receiver);
	}
}
